import time
from flask import Blueprint, jsonify, request
from flask_jwt_extended import jwt_required
from libs.conn import *
from libs.utils import *
from libs.TSData import TSData

if not os.path.exists(detection_values_dir):
    os.makedirs(detection_values_dir)

detection_values_bp = Blueprint('detection_values', __name__)

# 根据client_ids和types获取指定设备的参数
@detection_values_bp.route('/api/get_detection_values_by_client_ids', methods=['POST'])
@jwt_required()
def get_detection_values_by_client_ids():
    client_ids = request.json.get('client_ids')
    value_types = request.json.get('types')
    rows = fetchall(f'SELECT * FROM detection_values WHERE client_id IN ({",".join(["?"]*len(client_ids))}) AND type IN ({",".join(["?"]*len(value_types))})', tuple(client_ids + value_types))
    return { 'status': 'ok', 'data': rows }


@detection_values_bp.route('/api/get_detection_values', methods=['GET'])
@jwt_required()
def get_detection_values():
    client_id = request.args.get('client_id')
    value_type = request.args.get('type')
    page_size = int(request.args.get('page_size'))
    page_current = int(request.args.get('page_current'))
    params = []
    sql = "FROM detection_values WHERE 1=1"
    if is_string_valid(client_id):
        sql += " AND client_id = ?"
        params.append(client_id)
    if is_string_valid(value_type):
        sql += " AND type = ?"
        params.append(value_type)
    offset = (page_current - 1) * page_size
    rows = fetchall("SELECT * " + sql + " LIMIT ? OFFSET ?", tuple(params + [page_size, offset]))
    total_count = fetchvalue("SELECT COUNT(*) " + sql, tuple(params,))
    return { 'status': 'ok', 'data': rows, 'page_total': total_count }

# 获取指定设备当前的用电参数
@detection_values_bp.route('/api/get_client_detection_values', methods=['POST'])
@jwt_required()
def get_client_detection_values():
    client_id = request.json.get('client_id')
    row = fetchone("SELECT * FROM detection_values WHERE client_id = ?", (client_id,))
    return { 'status': 'ok', 'data': row }

# 获取指定设备的用电参数历史数据
@detection_values_bp.route('/api/get_client_detection_values_history', methods=['POST'])
@jwt_required()
def get_client_detection_values_history():
    # 需要指定开始时间和结束时间
    client_id = request.json.get('client_id')
    start_time = parse_time(request.json.get('start_time'), '%Y-%m-%d %H:%M:%S')
    count = int(request.json.get('count'))
    step = int(request.json.get('step'))
    params = request.json.get('params')
    if not is_string_valid(client_id):
        return { 'status': 'error', 'message': 'client_id is required' }
    result = {}
    for param in params:
        if param in param_configs.keys():
            data = TSData.read_dates_range_avg(
                start_time, 
                count,
                step,
                data_dir = os.path.join(detection_values_dir, client_id, param),
                value_size = param_configs[param]['value_size'],
                second_step = param_configs[param]['second_step']
                )
            result[param] = {
                'config': param_configs[param],
                'data': data
            }
    return { 'status': 'ok', 'data': result }



# 时间同步
@detection_values_bp.route('/api/sync_time', methods=['GET'])
def sync_time():
    return { 'status': 'ok', 'datetime': datetime.now().strftime('%Y-%m-%d %H:%M:%S') }

# 上传当前电压
@detection_values_bp.route('/api/upload_elec_current', methods=['POST'])
def upload_elec_current():
    client_id = request.json.get('client_id')
    voltage = float(request.json.get('voltage'))
    datetime_str = request.json.get('datetime')
    the_datetime = parse_time(datetime_str, '%Y-%m-%d %H:%M:%S')

    # 如果时间与当前时间间隔相差超过1小时，说明时间不同步
    if abs((the_datetime - datetime.now()).total_seconds()) > 3600:
        return { 'status': 'error', 'msg': 'Time is not synchronized', 'tag': 'sync_time' }, 200

    # 记录数据
    client_dir = os.path.join(detection_values_dir, client_id, 'voltage')
    seconds = TSData.calculate_second(the_datetime)
    TSData.today(data_dir=client_dir, value_size=param_configs['voltage']['value_size'], second_step=param_configs['voltage']['second_step']).write(seconds, int(voltage * 10))

    print(client_id, voltage, datetime_str)
    return { 'status': 'ok' }

# 上传电压数据文件
@detection_values_bp.route('/api/upload_elec_data', methods=['POST'])
def upload_file():
    client_id = request.form.get('client_id')
    data_date = datetime.strptime(request.form.get('data_date'), '%Y-%m-%d')
    trunk = request.form.get('trunk')
    if client_id is None:
        return { 'status': 'error', 'msg': 'No client_id provided' }, 200
    client = fetchone("SELECT * FROM clients WHERE client_id = ?", (client_id,))
    if client is None:
        return { 'status': 'error', 'msg': 'Invalid client_id'}, 200
    if 'file' not in request.files:
        return { 'status': 'error', 'msg': 'No file part'}, 200
    
    file = request.files['file']
    
    if file.filename == '':
        return { 'status': 'error', 'msg': 'No selected file'}, 200

    client_dir = os.path.join(detection_values_dir, client_id, 'voltage')
    filename = os.path.join(client_dir, f'{data_date.strftime("%Y-%m-%d")}_second.bin')

    if trunk == '1':
        # 分片传输，需要合并
        trunk_index = int(request.form.get('trunk_index'))
        trunk_total = int(request.form.get('trunk_total'))
        file_hash = request.form.get('file_hash')
        temp_name = os.path.join(client_dir, f'{data_date.strftime("%Y-%m-%d")}.temp')
        # 写入临时文件
        if trunk_index == 1:
            os.remove(temp_name) if os.path.exists(temp_name) else None # 清空临时文件
        with open(temp_name, 'ab') as f:
            f.write(file.read())
        if trunk_index == trunk_total:
            # 最后一个分片，检测文件hash是否一致(不检测hash了，因为如果上传today数据过程中产生了新的数据时，hash会不一致)
            # if file_hash == calculate_md5(temp_name):
            with open(filename, 'wb') as f:
                f.write(open(temp_name, 'rb').read())
            os.remove(temp_name)
            return { 'status': 'ok', 'msg': 'File uploaded successfully' }, 200
            # else:
            #     os.remove(temp_name)
            #     return { 'status': 'error', 'msg': 'File hash mismatch'}, 200
        else:
            return { 'status': 'ok', 'msg': 'Trunk received' }, 200
    else:
        if not os.path.exists(client_dir):
            os.makedirs(client_dir)
        file.save(filename)
        return { 'status': 'ok', 'msg': 'File uploaded successfully' }, 200

# 检测是否需要上传
@detection_values_bp.route('/api/check_elec_upload', methods=['POST'])
def check_elec_upload():
    client_id = request.json.get('client_id')
    data_date = datetime.strptime(request.json.get('data_date'), '%Y-%m-%d')
    file_hash = request.json.get('file_hash')
    if client_id is None:
        return { 'status': 'error', 'msg': 'No client_id provided' }, 200
    client = fetchone("SELECT * FROM clients WHERE client_id = ?", (client_id,))
    if client is None:
        return { 'status': 'error', 'msg': 'Invalid client_id'}, 200
    client_dir = os.path.join(detection_values_dir, client_id)
    filename = os.path.join(client_dir, f'{data_date.strftime("%Y-%m-%d")}_second.bin')
    if os.path.exists(filename):
        print(file_hash, calculate_md5(filename))
        if file_hash == calculate_md5(filename):
            return { 'status': 'ok', 'msg': 'File exists', 'filename': filename}, 200
        else:
            return { 'status': 'error', 'msg': 'File exists but hash mismatch', 'filename': filename}, 200
    else:
        return { 'status': 'error', 'msg': 'File not exists', 'filename': filename}, 200
    

# 计算文件的 MD5 值
def calculate_md5(file_path):
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()